// @Author EthanScriptOn
// @Desc
package mysql_define

import (
	"fmt"
	"gitee.com/fatzeng/srf_switch_basic_components/common/identity"
	"gitee.com/fatzeng/srf_switch_basic_components/switch_log"
	"gitee.com/fatzeng/srf_switch_basic_components/util"
	"gitee.com/fatzeng/srf_switch_expansion_package/extend_config"
	"gitee.com/fatzeng/srf_switch_expansion_package/extend_operator/mysql_operator"
	"gitee.com/fatzeng/srf_switch_expansion_package/extend_param_builder"
	"gitee.com/fatzeng/srf_switch_expansion_package/extend_param_collector"
	"gitee.com/fatzeng/srf_switch_expansion_package/extend_parser"
	"gitee.com/fatzeng/srf_switch_stream_bridge/bridge"
	"gitee.com/fatzeng/srf_switch_stream_bridge/framework/operator"
	"gitee.com/fatzeng/srf_switch_stream_bridge/framework/operator/op_example"
	"gitee.com/fatzeng/srf_switch_stream_bridge/param_collector"
	"gitee.com/fatzeng/srf_switch_stream_bridge/result_collector"
	"reflect"
	"time"
)

const MYSQL_BACKGROUND_TIME_OUT = "MYSQL_BACKGROUND_TIME_OUT"
const MYSQL_BACKGROUND_DELAYED = "MYSQL_BACKGROUND_DELAYED"
const MYSQL_BACKGROUND_LOOP = "MYSQL_BACKGROUND_LOOP"
const MYSQL_BACKGROUND_BRIDGE_CONFIG = "MYSQL_BACKGROUND_BRIDGE_CONFIG"

var mysqlBackgroundTimeOutOnceInitializer = util.GenerateOnceInitializer(func() (result interface{}, err error) {
	mysqlTimeOutOperator := op_example.TimeoutDetectionMultiChannelDataOperator{
		IdentityInformationCarrier: identity.GenerateIdentityInformationCarrierWithIdentity(MYSQL_BACKGROUND_TIME_OUT),
	}
	err = operator.AddOperator(&mysqlTimeOutOperator)
	if err != nil {
		return nil, err
	}
	return &mysqlTimeOutOperator, nil
})

func getMysqlBackgroundTimeoutOperator() operator.MultiChannelDataOperator {
	get, err := mysqlBackgroundTimeOutOnceInitializer.Get()
	if err != nil {
		switch_log.Logger().Error("get mysql timeout operator error: ", err)
		panic(err)
	}
	return get.(operator.MultiChannelDataOperator)
}

var mysqlBackgroundDelayedOnceInitializer = util.GenerateOnceInitializer(func() (result interface{}, err error) {
	mysqlDelayedOperator := op_example.DelayedCallDetectionMultiChannelDataOperator{
		IdentityInformationCarrier: identity.GenerateIdentityInformationCarrierWithIdentity(MYSQL_BACKGROUND_DELAYED),
	}
	err = operator.AddOperator(&mysqlDelayedOperator)
	if err != nil {
		return nil, err
	}
	return &mysqlDelayedOperator, nil
})

func getMysqlBackgroundDelayedOperator() operator.MultiChannelDataOperator {
	get, err := mysqlBackgroundDelayedOnceInitializer.Get()
	if err != nil {
		switch_log.Logger().Error("get mysql delayed operator error: ", err)
		panic(err)
	}
	return get.(operator.MultiChannelDataOperator)
}

var mysqlBackgroundLoopOnceInitializer = util.GenerateOnceInitializer(func() (result interface{}, err error) {
	mysqlLoopOperator := mysql_operator.MysqlQueryOperator{
		IdentityInformationCarrier: identity.GenerateIdentityInformationCarrierWithIdentity(MYSQL_BACKGROUND_LOOP),
	}
	err = operator.AddOperator(&mysqlLoopOperator)
	if err != nil {
		return nil, err
	}
	return &mysqlLoopOperator, nil
})

func getMysqlBackgroundLoopOperator() operator.MultiChannelDataOperator {
	get, err := mysqlBackgroundLoopOnceInitializer.Get()
	if err != nil {
		switch_log.Logger().Error("get mysql loop operator error: ", err)
		panic(err)
	}
	return get.(operator.MultiChannelDataOperator)
}

func getOperatorConfigIdentifier() (identifier interface{}, err error) {
	timeoutInstance := getMysqlBackgroundTimeoutOperator()
	timeoutIdentifier, err := timeoutInstance.GenerateUniqueIdentifier()
	if err != nil {
		switch_log.Logger().Error("get mysql timeout operator identifier error: ", err)
		return nil, err
	}
	timeoutConfig := operator.TimeOutMultiChannelDataOperatorConfig{
		BasicMultiChannelDataOperatorConfig: operator.GenerateBasicMultiChannelDataOperatorConfig(MYSQL_BACKGROUND_TIME_OUT, timeoutIdentifier, nil),
		TimeOut:                             5 * time.Second,
	}
	err = operator.AddOperatorConfig(timeoutConfig)
	if err != nil {
		switch_log.Logger().Error("add mysql timeout operator config error: ", err)
		return nil, err
	}

	delayedInstance := getMysqlBackgroundDelayedOperator()
	delayedIdentifier, err := delayedInstance.GenerateUniqueIdentifier()
	if err != nil {
		switch_log.Logger().Error("get mysql delayed operator identifier error: ", err)
		return nil, err
	}
	delayedConfig := operator.DelayedMultiChannelDataOperatorConfig{
		BasicMultiChannelDataOperatorConfig: operator.GenerateBasicMultiChannelDataOperatorConfig(MYSQL_BACKGROUND_DELAYED, delayedIdentifier, timeoutConfig),
		Delayed:                             3 * time.Second,
	}
	err = operator.AddOperatorConfig(delayedConfig)
	if err != nil {
		switch_log.Logger().Error("add mysql delayed operator config error: ", err)
		return nil, err
	}

	loopOperator := getMysqlBackgroundLoopOperator()
	identifier, err = loopOperator.GenerateUniqueIdentifier()
	if err != nil {
		switch_log.Logger().Error("get mysql loop operator identifier error: ", err)
		return nil, err
	}
	loopConfig := operator.LoopMultiChannelDataOperatorConfig{
		BasicMultiChannelDataOperatorConfig: operator.GenerateBasicMultiChannelDataOperatorConfig(MYSQL_BACKGROUND_LOOP, identifier, delayedConfig),
	}
	err = operator.AddOperatorConfig(loopConfig)
	if err != nil {
		switch_log.Logger().Error("add mysql loop operator config error: ", err)
		return nil, err
	}
	return MYSQL_BACKGROUND_LOOP, nil
}

type SqlBackgroundLog struct {
}

type SqlBackgroundParamsCollector struct {
}

func (s *SqlBackgroundParamsCollector) Collect(emptyParam interface{}) error {
	params, ok := emptyParam.(*extend_param_collector.SqlParams)
	if !ok {
		return fmt.Errorf("param type error")
	}
	params.Command.WriteString("select * from db where id = ${id}")
	params.CommandArgs["id"] = "1"
	return nil
}

func (s *SqlBackgroundParamsCollector) ShouldExecute() bool {
	return true
}

func mysqlBackgroundBridgeConfigParamCollector() []param_collector.BridgeParamCollector {
	return []param_collector.BridgeParamCollector{&SqlBackgroundParamsCollector{}}
}

func MysqlBackgroundBridgeConfig() *bridge.BridgeConfig {
	loopOperator := getMysqlBackgroundLoopOperator()
	identifier, err := loopOperator.GenerateUniqueIdentifier()
	if err != nil {
		switch_log.Logger().Error("get mysql loop operator identifier error: ", err)
		return nil
	}
	configIdentifier, err := getOperatorConfigIdentifier()
	if err != nil {
		switch_log.Logger().Error("get mysql operator config identifier error: ", err)
		return nil
	}
	return &bridge.BridgeConfig{
		BridgeIdentifier:                   MYSQL_BACKGROUND_BRIDGE_CONFIG,
		DataSource:                         extend_config.MYSQL,
		OperatorConfigIdentifier:           configIdentifier,
		MultiChannelDataOperatorIdentifier: identifier,
		ParamsCollectors:                   mysqlBackgroundBridgeConfigParamCollector,
		ParamType:                          reflect.TypeOf(new(extend_param_collector.SqlParams)),
		ParamsBuilder:                      &extend_param_builder.SqlParamsBuilder{},
		ResultType:                         reflect.TypeOf([]SqlBackgroundLog{}),
		ResultParser:                       &extend_parser.MysqlQueryResponseParser{},
		ResultCollector:                    &result_collector.LoopBridgeResultCollector{},
	}
}
